using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;

namespace JTLeigh.Tools.Development.CopySourceAsHtml
{

    /// <summary>
    /// Represents an HTML stylesheet.
    /// </summary>
    public sealed class HtmlStyleSheet
    {
        #region Fields

        private SortedList<string, HtmlStyle> _addedStyles;
        private SortedList<string, HtmlStyle> _reusableStyles;

        #endregion // Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="HtmlStyleSheet"/> class.
        /// </summary>
        public HtmlStyleSheet()
        {
            _addedStyles = new SortedList<string, HtmlStyle>();
            _reusableStyles = new SortedList<string, HtmlStyle>();
        }

        #endregion // Constructors

        #region Methods

        /// <summary>
        /// Adds a style to the stylesheet.
        /// </summary>
        /// <param name="name">The name of the style.</param>
        /// <param name="style">The style.</param>
        public void AddStyle(string name, HtmlStyle style)
        {
            Safety.AssertArgumentNotNull("name", name);
            Safety.AssertArgumentNotNull("style", style);

            _addedStyles.Add(name, style);
        }

        /// <summary>
        /// Adds a reusable style to the stylesheet if it doesn't already exist, or reuses the
        /// existing style if it does.
        /// </summary>
        /// <param name="prefix">The prefix used to calculate the style name.</param>
        /// <param name="style">The style.</param>
        /// <returns>The name of the style that was either added or reused.</returns>
        /// <remarks>
        /// <para>
        /// This method is used to eliminate duplicate styles in the stylesheet by finding styles
        /// with the same prefix and reusing them.
        /// </para>
        /// <para>
        /// Reusable style names are numbered starting with 1.  For example, if the prefix is xx,
        /// the reusable style names will be xx1, xx2, xx3, etc.
        /// </para>
        /// </remarks>
        public string AddReusableStyle(string prefix, HtmlStyle style)
        {
            int id;
            string name;

            Safety.AssertArgumentNotNull("prefix", prefix);
            Safety.AssertArgumentNotNull("style", style);

            id = 1;
            foreach (var reusableStyle in _reusableStyles)
            {
                if (reusableStyle.Key.StartsWith(prefix, StringComparison.Ordinal))
                {
                    if (reusableStyle.Value.Equals(style))
                    {
                        return reusableStyle.Key;
                    }
                    id++;
                }
            }
            name = String.Format(CultureInfo.InvariantCulture, "{0}{1}", prefix, id);
            _reusableStyles[name] = style;
            return name;
        }

        /// <summary>
        /// Gets the HTML representation of the stylesheet.
        /// </summary>
        /// <param name="stripLineBreaks"></param>
        /// <returns></returns>
        public string GetHtml(bool stripLineBreaks)
        {
            StringBuilder content;

            content = new StringBuilder();
            content.Append("<style type=\"text/css\">");
            if (!stripLineBreaks)
            {
                content.Append("\r\n");
            }
            foreach (string key in _addedStyles.Keys)
            {
                content.AppendFormat(".{0} {{ {1} }}", key, _addedStyles[key]);
                if (!stripLineBreaks)
                {
                    content.AppendLine();
                }
            }
            foreach (string key in _reusableStyles.Keys)
            {
                content.AppendFormat(".{0} {{ {1} }}", key, _reusableStyles[key]);
                if (!stripLineBreaks)
                {
                    content.AppendLine();
                }
            }
            content.Append("</style>");
            if (!stripLineBreaks)
            {
                content.AppendLine();
            }
            return content.ToString();
        }

        #endregion // Methods
    }

}
